///\file model.hh
///\brief contient la définition d'un modèle OpenGL. Classe : Model.
///\author Allan BLANCHARD
#ifndef _MODEL
#define _MODEL

#include <GL/glew.h>

///\class Model
///\brief permet de charger un modèle OpenGL au format OFF
///
///restriction pour le moment : on ne peut charger que des modèles triangulés, 
///les quads viendront (peut être) plus tard.
class Model{
public:
  static unsigned int totalsommets; ///< nombre total de sommets chargés
  static unsigned int totalfaces; ///< nombre total de faces chargées

private:
  int ncoords;   ///< nombre de coordonnées de tous les types
                 ///par exemple, 3 coords spatiales + 3 coords de normales
  float* coords; ///< liste de toutes les coordonnées
  unsigned int nv; ///< nombre de sommets

  GLubyte* texture;///< texture
  int texw; ///< largeur texture
  int texh; ///< hauteur texture
  GLuint texid; ///< Texture ID

  unsigned int* indices; ///< liste des indices des faces
  unsigned int ni; ///< nombre de faces

  bool transparent; ///< Activer la transparence
  float amb[4]; ///< Material : ambient
  float dif[4]; ///< Material : diffuse
  float spe[4]; ///< Material : specular
  float emi[4]; ///< Material : emission
  float shi;    ///< Material : shininess

  float xmin; ///< Valeur minimale sur x
  float xmax; ///< Valeur maximale sur x
  float ymin; ///< Valeur minimale sur y
  float ymax; ///< Valeur maximale sur y
  float zmin; ///< Valeur minimale sur z
  float zmax; ///< Valeur maximale sur z

  bool vbo;  ///< Le modèle est-il en mode VBO ?
  GLuint buffer; ///< buffer vertex VBO
  GLuint index_buffer; ///< buffer indices VBO

  ///\brief cette méthode permet de centrer la modèle pendant le chargement
  ///du fichier.
  void center();
  
  ///\brief cette méthode effectue le calcul des normales pendant le chargement
  void computenorms();
  
  ///\brief cette méthode met le modèle dans une boite de 1*1*1
  void boxify();

  ///\brief cette méthode charge la texture du fichier "name"
  ///\param name : nom du fichier
  void loadtex(const char* name);

   
  ///\brief Constructeur de Copie
  ///privé par sécurité
  ///\param m modèle à copier
  Model(const Model& m);

public:
  ///\brief Constructeur
  ///construit un modèle à partir d'un fichier OpenGL
  ///\param file chemin vers un fichier OFF
  ///\param transparent activer ou non la transparence
  Model(const char* file, bool transparent = false);
 
  ///\brief 
  ///dispositif anti-glut-debile
  void free();

  ///\brief Destructeur
  virtual ~Model();

  ///\brief 
  ///dessine le modèle dans la fenêtre OpenGL
  virtual void draw() const;

  ///\brief
  ///permet de redimensionner le modèle selon la valeur factor
  ///\param factor facteur de redimensionnement
  void resize(float factor);

  ///\brief
  ///permet de fixer la valeur de la couleur ambient
  void setAmbient(float r, float g, float b, float a = 1.0);

  ///\brief
  ///permet de fixer la valeur de la couleur diffuse
  void setDiffuse(float r, float g, float b, float a = 1.0);
  
  ///\brief
  ///permet de fixer la valeur de la couleur specular
  void setSpecular(float r, float g, float b, float a = 1.0);

  ///\brief
  ///permet de fixer la valeur de shininess
  void setShininess(float val);

  ///\brief
  ///permet de fixer la valeur de la couleur emission
  void setEmission(float r, float g, float b, float a = 1.0);

  ///\brief
  ///envoie le modèle en tant que VBO
  void toVBO();

  ///\brief
  ///\return nombre de coordonnées de points
  ///\warning trois fois le nombre de points
  inline unsigned int getNbVertices() const { return 3*nv; }
  
  ///\brief
  ///\return nombre total d'indices
  ///\warning trois fois le nombre de faces
  inline unsigned int getNbIndices() const { return 3*ni; }    

  ///\brief
  ///\return valeur maximale sur x;
  inline float getxmax() const { return xmax; }

  ///\brief
  ///\return valeur minimale sur x;
  inline float getxmin() const { return xmin; }

  ///\brief
  ///\return valeur maximale sur y;
  inline float getymax() const { return ymax; }

  ///\brief
  ///\return valeur minimale sur y;
  inline float getymin() const { return ymin; }

  ///\brief
  ///\return valeur maximale sur z;
  inline float getzmax() const { return zmax; }

  ///\brief
  ///\return valeur minimale sur z;
  inline float getzmin() const { return zmin; }

  ///\brief
  ///modèle transparent ?
  ///\return transparent
  inline bool estTransparent() const{ return transparent; }
};

#endif
